package com.yoo.module_base.view.index.slideview

import android.content.Context
import android.graphics.PointF
import android.os.Handler
import android.view.View
import android.view.ViewGroup
import android.view.animation.Interpolator
import androidx.annotation.FloatRange
import androidx.annotation.IntRange
import androidx.recyclerview.widget.RecyclerView
import com.yoo.module_base.R
import com.yoo.module_base.utils.ScreenUtils.dip2px
import com.yoo.module_base.view.index.slideview.hp.IndexSlideCardSetting
import com.yoo.module_base.view.index.slideview.hp.IndexSlideCardSmoothScroller
import com.yoo.module_base.view.index.slideview.hp.IndexSlideCardState

class IndexSlideCardLayoutManager @JvmOverloads constructor(
    private val context: Context,
    listener: IndexSlideCardListener = IndexSlideCardListener.DEFAULT
) : RecyclerView.LayoutManager(), RecyclerView.SmoothScroller.ScrollVectorProvider {
    var cardStackListener = IndexSlideCardListener.DEFAULT
    private val setting: IndexSlideCardSetting = IndexSlideCardSetting()
    private val state: IndexSlideCardState = IndexSlideCardState()

    init {
        cardStackListener = listener
    }

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT
        )
    }

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, s: RecyclerView.State) {
        update(recycler)
        if (s.didStructureChange()) {
            val topView: View? = topView
            if (topView != null) {
                cardStackListener.onCardAppeared(this.topView, state.topPosition)
            }
        }
    }

    override fun canScrollHorizontally(): Boolean {
        return setting.swipeableMethod.canSwipe() && setting.canScrollHorizontal
    }

    override fun canScrollVertically(): Boolean {
        return setting.swipeableMethod.canSwipe() && setting.canScrollVertical
    }

    override fun scrollHorizontallyBy(
        dx: Int,
        recycler: RecyclerView.Recycler,
        s: RecyclerView.State
    ): Int {
        if (state.topPosition == getItemCount()) {
            return 0
        }
        when (state.status) {
            IndexSlideCardState.Status.Idle -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dx -= dx
                update(recycler)
                return dx
            }

            IndexSlideCardState.Status.Dragging -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dx -= dx
                //todo 待添加BaseConfig
//                if (BaseConfig.Companion.getGetInstance()
//                        .getBoolean(SpName.INSTANCE.getUserCard() + topPosition, false)
//                ) {
//                    if (!BaseConfig.Companion.getGetInstance()
//                            .getBoolean(SpName.INSTANCE.isMember(), false)
//                    ) {
//                        if (state.dx < 0) {
//                            if (BaseConfig.Companion.getGetInstance()
//                                    .getInt(SpName.INSTANCE.getRemainingBrowseBNum(), 0) <= 0
//                            ) {
//                                MemberDialogShow.INSTANCE.memberBuyShow(2, context)
//                                state.dx = -50
//                            }
//                        } else if (state.dx > 0) {
//                            if (BaseConfig.Companion.getGetInstance()
//                                    .getInt(SpName.INSTANCE.getRemainingWlmNum(), 0) <= 0
//                            ) {
//                                MemberDialogShow.INSTANCE.memberBuyShow(1, context)
//                                state.dx = 50
//                            }
//                        }
//                    }
//                }
                update(recycler)
                return dx
            }

            IndexSlideCardState.Status.RewindAnimating -> {
                state.dx -= dx
                update(recycler)
                return dx
            }

            IndexSlideCardState.Status.AutomaticSwipeAnimating -> if (setting.swipeableMethod.canSwipeAutomatically()) {
                state.dx -= dx
                update(recycler)
                return dx
            }

            IndexSlideCardState.Status.AutomaticSwipeAnimated -> {}
            IndexSlideCardState.Status.ManualSwipeAnimating -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dx -= dx
                update(recycler)
                return dx
            }

            IndexSlideCardState.Status.ManualSwipeAnimated -> {}
        }
        return 0
    }

    override fun scrollVerticallyBy(
        dy: Int,
        recycler: RecyclerView.Recycler,
        s: RecyclerView.State
    ): Int {
        if (state.topPosition == getItemCount()) {
            return 0
        }
        when (state.status) {
            IndexSlideCardState.Status.Idle -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dy -= dy
                update(recycler)
                return dy
            }

            IndexSlideCardState.Status.Dragging -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dy -= dy
                update(recycler)
                return dy
            }

            IndexSlideCardState.Status.RewindAnimating -> {
                state.dy -= dy
                update(recycler)
                return dy
            }

            IndexSlideCardState.Status.AutomaticSwipeAnimating -> if (setting.swipeableMethod.canSwipeAutomatically()) {
                state.dy -= dy
                update(recycler)
                return dy
            }

            IndexSlideCardState.Status.AutomaticSwipeAnimated -> {}
            IndexSlideCardState.Status.ManualSwipeAnimating -> if (setting.swipeableMethod.canSwipeManually()) {
                state.dy -= dy
                update(recycler)
                return dy
            }

            IndexSlideCardState.Status.ManualSwipeAnimated -> {}
        }
        return 0
    }

    override fun onScrollStateChanged(s: Int) {
        when (s) {
            RecyclerView.SCROLL_STATE_IDLE -> if (state.targetPosition == RecyclerView.NO_POSITION) {
                state.next(IndexSlideCardState.Status.Idle)
                state.targetPosition = RecyclerView.NO_POSITION
            } else if (state.topPosition == state.targetPosition) {
                state.next(IndexSlideCardState.Status.Idle)
                state.targetPosition = RecyclerView.NO_POSITION
            } else {
                if (state.topPosition < state.targetPosition) {
                    //todo 待添加
//                    if (BaseConfig.Companion.getGetInstance()
//                            .getBoolean(SpName.INSTANCE.getUserCard() + topPosition, false)
//                    ) {
//                        if (!BaseConfig.Companion.getGetInstance()
//                                .getBoolean(SpName.INSTANCE.isMember(), false)
//                        ) {
//                            if (state.dx < 0) {
//                                if (BaseConfig.Companion.getGetInstance()
//                                        .getInt(SpName.INSTANCE.getRemainingBrowseBNum(), 0) <= 0
//                                ) {
//                                    state.next(CardStackState.Status.Idle)
//                                    state.targetPosition = RecyclerView.NO_POSITION
//                                    break
//                                }
//                            } else if (state.dx > 0) {
//                                if (BaseConfig.Companion.getGetInstance()
//                                        .getInt(SpName.INSTANCE.getRemainingWlmNum(), 0) <= 0
//                                ) {
//                                    state.next(CardStackState.Status.Idle)
//                                    state.targetPosition = RecyclerView.NO_POSITION
//                                    break
//                                }
//                            }
//                        }
//                    }
                    smoothScrollToNext(state.targetPosition)
                } else {
                    smoothScrollToPrevious(state.targetPosition)
                }
            }

            RecyclerView.SCROLL_STATE_DRAGGING -> if (setting.swipeableMethod.canSwipeManually()) {
                state.next(IndexSlideCardState.Status.Dragging)
            }

            RecyclerView.SCROLL_STATE_SETTLING -> {}
        }
    }

    override fun computeScrollVectorForPosition(targetPosition: Int): PointF? {
        return null
    }

    override fun scrollToPosition(position: Int) {
        if (setting.swipeableMethod.canSwipeAutomatically()) {
            if (state.canScrollToPosition(position, getItemCount())) {
                state.topPosition = position
                requestLayout()
            }
        }
    }

    override fun smoothScrollToPosition(
        recyclerView: RecyclerView,
        s: RecyclerView.State,
        position: Int
    ) {
        if (setting.swipeableMethod.canSwipeAutomatically()) {
            if (state.canScrollToPosition(position, getItemCount())) {
                smoothScrollToPosition(position)
            }
        }
    }

    val cardStackSetting: IndexSlideCardSetting
        get() = setting
    val cardStackState: IndexSlideCardState
        get() = state

    fun updateProportion(x: Float, y: Float) {
        if (topPosition < getItemCount()) {
            val view: View? = findViewByPosition(topPosition)
            if (view != null) {
                val half: Float = height / 2.0f
                state.proportion = -(y - half - view.top) / half
            }
        }
    }

    private fun update(recycler: RecyclerView.Recycler) {
        state.width = width
        state.height = height
        if (state.isSwipeCompleted) {
            topView?.let { removeAndRecycleView(it, recycler) }
            val direction: IndexSlideCardDirection = state.direction
            state.next(state.status.toAnimatedStatus())
            state.topPosition++
            state.dx = 0f
            state.dy = 0f
            if (state.topPosition == state.targetPosition) {
                state.targetPosition = RecyclerView.NO_POSITION
            }
            Handler().post {
                cardStackListener.onCardSwiped(direction)
                val topView: View? = topView
                if (topView != null) {
                    cardStackListener.onCardAppeared(topView, state.topPosition)
                }
            }
        }
        detachAndScrapAttachedViews(recycler)
        val parentTop: Int = paddingTop
        val parentLeft: Int = paddingLeft
        val parentRight: Int = width - paddingLeft
        val parentBottom: Int = height - paddingBottom
        var i: Int = state.topPosition
        while (i < state.topPosition + setting.visibleCount && i < getItemCount()) {
            val child: View = recycler.getViewForPosition(i)
            addView(child, 0)
            measureChildWithMargins(child, 0, 0)
            layoutDecoratedWithMargins(child, parentLeft, parentTop, parentRight, parentBottom)
            resetTranslation(child)
            resetScale(child)
            resetRotation(child)
            resetOverlay(child)
            if (i == state.topPosition) {
                updateTranslation(child)
                resetScale(child)
                updateRotation(child)
                updateOverlay(child)
            } else {
                val currentIndex: Int = i - state.topPosition
                updateTranslation(child, currentIndex)
                //不需要缩放效果
                //updateScale(child, currentIndex)
                resetRotation(child)
                resetOverlay(child)
            }
            i++
        }
        if (state.status.isDragging) {
            cardStackListener.onCardDragging(state.direction, state.ratio)
        }
    }

    private fun updateRewind(recycler: RecyclerView.Recycler) {
        state.width = width
        state.height = height
        detachAndScrapAttachedViews(recycler)
        val parentTop: Int = paddingTop
        val parentLeft: Int = paddingLeft
        val parentRight: Int = width - paddingLeft
        val parentBottom: Int = height - paddingBottom
        var i: Int = state.topPosition
        while (i < state.topPosition + setting.visibleCount && i < getItemCount()) {
            val child: View = recycler.getViewForPosition(i)
            addView(child, 0)
            measureChildWithMargins(child, 0, 0)
            layoutDecoratedWithMargins(child, parentLeft, parentTop, parentRight, parentBottom)
            resetTranslation(child)
            resetScale(child)
            resetRotation(child)
            resetOverlay(child)
            i++
        }
        if (state.status.isDragging) {
            cardStackListener.onCardDragging(state.direction, state.ratio)
        }
    }

    private fun updateTranslation(view: View) {
        view.translationX = state.dx
        view.translationY = state.dy
    }

    private fun updateTranslation(view: View, index: Int) {
        val nextIndex = index - 1
        val translationPx: Int = dip2px(context, setting.translationInterval)
        val currentTranslation = (index * translationPx).toFloat()
        val nextTranslation = (nextIndex * translationPx).toFloat()
        val targetTranslation: Float =
            currentTranslation - (currentTranslation - nextTranslation) * state.ratio
        when (setting.stackFrom) {
            IndexSlideCardFrom.None -> {}
            IndexSlideCardFrom.Top -> view.translationY = -targetTranslation
            IndexSlideCardFrom.TopAndLeft -> {
                view.translationY = -targetTranslation
                view.translationX = -targetTranslation
            }

            IndexSlideCardFrom.TopAndRight -> {
                view.translationY = -targetTranslation
                view.translationX = targetTranslation
            }

            IndexSlideCardFrom.Bottom -> view.translationY = targetTranslation
            IndexSlideCardFrom.BottomAndLeft -> {
                view.translationY = targetTranslation
                view.translationX = -targetTranslation
            }

            IndexSlideCardFrom.BottomAndRight -> {
                view.translationY = targetTranslation
                view.translationX = targetTranslation
            }

            IndexSlideCardFrom.Left -> view.translationX = -targetTranslation
            IndexSlideCardFrom.Right -> view.translationX = targetTranslation
        }
    }

    private fun resetTranslation(view: View) {
        view.translationX = 0.0f
        view.translationY = 0.0f
    }

    private fun updateScale(view: View, index: Int) {
        val nextIndex = index - 1
        val currentScale: Float = 1.0f - index * (1.0f - setting.scaleInterval)
        val nextScale: Float = 1.0f - nextIndex * (1.0f - setting.scaleInterval)
        val targetScale: Float = currentScale + (nextScale - currentScale) * state.ratio
        if (!java.lang.Float.isNaN(targetScale)) {
            when (setting.stackFrom) {
                IndexSlideCardFrom.None -> {
                    view.scaleX = targetScale
                    view.scaleY = targetScale
                }

                IndexSlideCardFrom.Top -> view.scaleX = targetScale
                IndexSlideCardFrom.TopAndLeft -> view.scaleX = targetScale
                IndexSlideCardFrom.TopAndRight -> view.scaleX = targetScale
                IndexSlideCardFrom.Bottom -> view.scaleX = targetScale
                IndexSlideCardFrom.BottomAndLeft -> view.scaleX = targetScale
                IndexSlideCardFrom.BottomAndRight -> view.scaleX = targetScale
                IndexSlideCardFrom.Left ->                     // TODO Should handle ScaleX
                    view.scaleY = targetScale

                IndexSlideCardFrom.Right ->                     // TODO Should handle ScaleX
                    view.scaleY = targetScale
            }
        }
    }

    private fun resetScale(view: View) {
        view.scaleX = 1.0f
        view.scaleY = 1.0f
    }

    private fun updateRotation(view: View) {
        val degree: Float = state.dx * setting.maxDegree / width * state.proportion
        view.rotation = degree
    }

    private fun resetRotation(view: View) {
        view.rotation = 0.0f
    }

    private fun updateOverlay(view: View) {
        val leftOverlay = view.findViewById<View>(R.id.left_overlay)
        if (leftOverlay != null) {
            leftOverlay.alpha = 0.0f
        }
        val rightOverlay = view.findViewById<View>(R.id.right_overlay)
        if (rightOverlay != null) {
            rightOverlay.alpha = 0.0f
        }
        val direction: IndexSlideCardDirection = state.direction
        //手动更改卡片是否喜欢的不透明度
        val alpha: Float = setting.overlayInterpolator.getInterpolation(state.ratio) * 1.2f
        when (direction) {
            IndexSlideCardDirection.Left -> if (leftOverlay != null) {
                leftOverlay.alpha = alpha
            }

            IndexSlideCardDirection.Right -> if (rightOverlay != null) {
                rightOverlay.alpha = alpha
            }

            IndexSlideCardDirection.Top -> Unit
            IndexSlideCardDirection.Bottom -> Unit
        }
    }

    private fun resetOverlay(view: View) {
        val leftOverlay = view.findViewById<View>(R.id.left_overlay)
        if (leftOverlay != null) {
            leftOverlay.alpha = 0.0f
        }
        val rightOverlay = view.findViewById<View>(R.id.right_overlay)
        if (rightOverlay != null) {
            rightOverlay.alpha = 0.0f
        }
    }

    private fun smoothScrollToPosition(position: Int) {
        if (state.topPosition < position) {
            smoothScrollToNext(position)
        } else {
            smoothScrollToPrevious(position)
        }
    }

    private fun smoothScrollToNext(position: Int) {
        state.proportion = 0.0f
        state.targetPosition = position
        val scroller =
            IndexSlideCardSmoothScroller(IndexSlideCardSmoothScroller.ScrollType.AutomaticSwipe, this)
        scroller.targetPosition = state.topPosition
        startSmoothScroll(scroller)
    }

    private fun smoothScrollToPrevious(position: Int) {
        val topView: View? = topView
        if (topView != null) {
            cardStackListener.onCardDisappeared(this.topView, state.topPosition)
        }
        state.proportion = 0.0f
        state.targetPosition = position
        state.topPosition--
        val scroller =
            IndexSlideCardSmoothScroller(IndexSlideCardSmoothScroller.ScrollType.AutomaticRewind, this)
        scroller.targetPosition = state.topPosition
        startSmoothScroll(scroller)
    }

    val topView: View?
        get() = findViewByPosition(state.topPosition)
    var topPosition: Int
        get() = state.topPosition
        set(topPosition) {
            state.topPosition = topPosition
        }

    fun setStackFrom(stackFrom: IndexSlideCardFrom) {
        setting.stackFrom = stackFrom
    }

    fun setVisibleCount(@IntRange(from = 1) visibleCount: Int) {
        require(visibleCount >= 1) { "VisibleCount must be greater than 0." }
        setting.visibleCount = visibleCount
    }

    fun setTranslationInterval(@FloatRange(from = 0.0) translationInterval: Float) {
        if (translationInterval < 0.0f) {
            throw IllegalArgumentException("TranslationInterval must be greater than or equal 0.0f")
        }
        setting.translationInterval = translationInterval
    }

    fun setScaleInterval(@FloatRange(from = 0.0) scaleInterval: Float) {
        if (scaleInterval < 0.0f) {
            throw IllegalArgumentException("ScaleInterval must be greater than or equal 0.0f.")
        }
        setting.scaleInterval = scaleInterval
    }

    fun setSwipeThreshold(@FloatRange(from = 0.0, to = 1.0) swipeThreshold: Float) {
        if (swipeThreshold < 0.0f || 1.0f < swipeThreshold) {
            throw IllegalArgumentException("SwipeThreshold must be 0.0f to 1.0f.")
        }
        setting.swipeThreshold = swipeThreshold
    }

    fun setMaxDegree(@FloatRange(from = (-360.0f).toDouble(), to = 360.0) maxDegree: Float) {
        if (maxDegree < -360.0f || 360.0f < maxDegree) {
            throw IllegalArgumentException("MaxDegree must be -360.0f to 360.0f")
        }
        setting.maxDegree = maxDegree
    }

    fun setDirections(directions: List<IndexSlideCardDirection>) {
        setting.directions = directions
    }

    fun setCanScrollHorizontal(canScrollHorizontal: Boolean) {
        setting.canScrollHorizontal = canScrollHorizontal
    }

    fun setCanScrollVertical(canScrollVertical: Boolean) {
        setting.canScrollVertical = canScrollVertical
    }

    fun setSwipeableMethod(swipeableMethod: IndexSlideCardAbleMethod) {
        setting.swipeableMethod = swipeableMethod
    }

    fun setSwipeAnimationSetting(swipeAnimationSetting: IndexSlideCardAnimSetting?) {
        setting.swipeAnimationSetting = swipeAnimationSetting
    }

    fun setRewindAnimationSetting(rewindAnimationSetting: IndexSlideCardRewindAnimaSetting) {
        setting.rewindAnimationSetting = rewindAnimationSetting
    }

    fun setOverlayInterpolator(overlayInterpolator: Interpolator) {
        setting.overlayInterpolator = overlayInterpolator
    }
}